﻿// #define USE_UNSAFE // Define this to use faster unsafe methods.

using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace CParallelImageFilter
{
#if USE_UNSAFE
    public unsafe class BitmapBytesRGB24
#else
    public class BitmapBytesRGB24
#endif
    {
        // Provide public access to the picture's byte data.
#if USE_UNSAFE
        public byte* ImageBytes;
#else
        public byte[] ImageBytes;
#endif
        int RowSizeBytes;
        public const int PixelSizeBytes = 3;
        public const int PixelSizeBits = PixelSizeBytes * 8;

        // Save a reference to the bitmap.
        public BitmapBytesRGB24(Bitmap bm)
        {
            m_Bitmap = bm;
        }

        // A reference to the Bitmap.
        private Bitmap m_Bitmap;

        // Bitmap data.
        private BitmapData m_BitmapData;

        // Lock the bitmap's data.
        public void LockBitmap()
        {
            // Lock the bitmap data.
            Rectangle bounds = new Rectangle(
                0, 0, m_Bitmap.Width, m_Bitmap.Height);
            m_BitmapData = m_Bitmap.LockBits(bounds,
                ImageLockMode.ReadWrite,
                PixelFormat.Format24bppRgb);
            RowSizeBytes = m_BitmapData.Stride;

#if USE_UNSAFE
            // Set a pointer to the data.
            ImageBytes = (byte*)m_BitmapData.Scan0;
#else
            // Allocate room for the data.
            int total_size = m_BitmapData.Stride * m_BitmapData.Height;
            ImageBytes = new byte[total_size];

            // Copy the data into the ImageBytes array.
            Marshal.Copy(m_BitmapData.Scan0, ImageBytes,
                0, total_size);
#endif
        }

        // Copy the data back into the Bitmap
        // and release resources.
        public void UnlockBitmap()
        {
            // Copy the data back into the bitmap.
            int total_size = m_BitmapData.Stride * m_BitmapData.Height;
#if !USE_UNSAFE
            Marshal.Copy(ImageBytes, 0,
                m_BitmapData.Scan0, total_size);
#endif

            // Unlock the bitmap.
            m_Bitmap.UnlockBits(m_BitmapData);

            // Release resources.
            ImageBytes = null;
            m_BitmapData = null;
        }

        // Return a pixel's byte values.
        public void GetPixel(int x, int y, ref byte r, ref byte g, ref byte b)
        {
            int offset = y * RowSizeBytes + x * PixelSizeBytes;
            b = ImageBytes[offset];
            g = ImageBytes[offset + 1];
            r = ImageBytes[offset + 2];
        }

        // Set a pixel's byte values.
        public void SetPixel(int x, int y, byte r, byte g, byte b)
        {
            int offset = y * RowSizeBytes + x * PixelSizeBytes;
            ImageBytes[offset] = b;
            ImageBytes[offset + 1] = g;
            ImageBytes[offset + 2] = r;
        }
    }
}
